"""This module defines importers of different GIS data format.
"""
from django.contrib.gis import geos
from django.contrib.gis.gdal import DataSource
from osgeo import ogr
import time

from webmapper.geophotos import models

def FindFieldIndexByName(layer, name):
  """Find a field in layer by its name.
  Returns a number pointing to the field
  """
  layer_defn = layer.GetLayerDefn()
  for i in xrange(0, layer_defn.GetFieldCount()):
    if name == layer_defn.GetFieldDefn(i).GetName():
      return i
  return -1

class ImportError(Exception):
  def __init__(self, value):
    self.value = value
  
  def __str__(self):
    return "Import error."
  
class ShapefileImporter:
  def __init__(self):
    self.layer = None
    
  def AddGeometry(self, record, geom):
    """
    record: a models.Record instance
    geom_type: Geometry type
    geom: an osgeo.ogr.Geometry instance
    """
    geom_type = geom.geom_type.name
    geom = geos.fromstr(geom.wkt)
    if geom_type == "MultiPoint":
      record.point_geom = geom
    elif geom_type == "Point":
      record.point_geom = geos.MultiPoint(geom)
    elif geom_type == "MultiLineString":
      record.line_geom = geom
    elif geom_type == "LineString":
      record.line_geom = geos.MultiLineString(geom)
    elif geom_type == "MultiPolygon":
      record.polygon_geom = geom
    elif geom_type == "Polygon":
      record.polygon_geom = geos.MultiPolygon(geom)

  def Import(self, filename):
    dataset = DataSource(filename)
    self.layer = dataset[0]
    
    geom_type = self.layer.geom_type
    
    fields = {}
    name_field = -1
    alt_name_field = -1
    for i in xrange(0, self.layer.num_fields):
      fields[i] = self.layer.fields[i]
      if self.layer.fields[i].lower() == 'name':
        name_field = i
      if self.layer.fields[i].lower().find('name') >= 0:
        alt_name_field = i
    
    for feature in self.layer:
      # Create a GeoRecord as the master
      record = models.GeoRecord()
      self.AddGeometry(record, feature.geom)
      if name_field >= 0:
        record.name = feature.get(name_field)
      elif alt_name_field >= 0:
        record.name = feature.get(alt_name_field)
      
      # Create a series of Attribute
      attributes = []
      for i in xrange(0, feature.num_fields):
        attributes.append("%s: %s" % (feature.fields[i],
                                      str(feature.get(i))))
        
      record.description = "<br/>".join(attributes)
      record.save()
      print "record saved."

  
class GpxImporter:
  def __init__(self):
    self.waypoints_layer = None
    self.routes_layer = None
    self.tracks_layer = None
    self.route_points_layer = None
    self.track_points_layer = None
    self.stats = {"layers": 0, "features":0}
  
  def FindLayers(self, dataset):
    for i in xrange(0, dataset.GetLayerCount()):
      layer = dataset.GetLayer(i)
      name = layer.GetName()
      if name == "waypoints":
        self.waypoints_layer = dataset.GetLayer(i)
      elif name == "routes":
        self.routes_layer = dataset.GetLayer(i)
      elif name == "tracks":
        self.tracks_layer = dataset.GetLayer(i)
      elif name == "route_points":
        self.route_points_layer = dataset.GetLayer(i)
      elif name == "track_points":
        self.track_points_layer = dataset.GetLayer(i)
          
  def Import(self, filename):
    # Check file name
    driver = ogr.GetDriverByName("GPX")
    dataset = driver.Open(filename)
    
    # Get all layers
    self.FindLayers(dataset)
    
    # Import tracks
    track_id_fieldn = FindFieldIndexByName(self.tracks_layer, "number")
    name_fieldn = FindFieldIndexByName(self.tracks_layer, "name")
    tracks = {}
    feature = self.tracks_layer.GetNextFeature()
    last_track_number = None
    while feature:
      # Create and Save a track object
      track = models.Track()
      track.name = feature.GetField(name_fieldn)
      track.save()
      self.stats["layers"] += 1
      
      if feature.GetField(track_id_fieldn):
        last_track_number = feature.GetField(track_id_fieldn)
      else:
        last_track_number = track.id
      tracks[last_track_number] = track
      
      feature = self.tracks_layer.GetNextFeature()
      

    # Import track points
    feature = self.track_points_layer.GetNextFeature()
    fid_fieldn = FindFieldIndexByName(self.track_points_layer, "track_fid")
    time_fieldn = FindFieldIndexByName(self.track_points_layer, "time")
    ele_fieldn = FindFieldIndexByName(self.track_points_layer, "ele")
    while feature is not None:
      track_point = models.TrackPoint()
      track_point.point = geos.Point(feature.geometry().GetPoint())
      track_point.elevation = feature.GetFieldAsDouble(ele_fieldn)
      track_point.timestamp = time.mktime(
          (feature.GetFieldAsDateTime(time_fieldn) + [0, 0, 0, 0])[:9])
      
      # Set which track this point belongs to
      if tracks.has_key(feature.GetField(fid_fieldn)):
        track_point.track_ref = tracks[feature.GetField(fid_fieldn)]
      else:
        track_point.track_ref = tracks[last_track_number]
      
      track_point.save()
      self.stats["features"] += 1
      
      feature = self.track_points_layer.GetNextFeature()